/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package vamprest.api;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;
import vamprest.api.myexception.MyErrMsg;
import vamprest.api.myexception.MyException;

/**
 *
 * @author sav
 */
public abstract class AbstractFacade<T> {
    private String userDB = "vamp";
    private String pwdDB = "vamp";
    private Class<T> entityClass;
    @PersistenceUnit
    private EntityManagerFactory entityManagerFactory;

    public AbstractFacade(Class<T> entityClass) {
        this.entityClass = entityClass;
    }

    protected abstract EntityManager getEntityManager();

    public void create(T entity, String[] controlAccess) throws MyException {
        checkAccessControl(controlAccess);
        getEntityManager().persist(entity);
    }

    public T edit(T entity, String[] controlAccess) throws MyException {
        checkAccessControl(controlAccess);
        return getEntityManager().merge(entity);
    }

    public void remove(T entity, String[] controlAccess) throws MyException {
        checkAccessControl(controlAccess);
        getEntityManager().remove(getEntityManager().merge(entity));
    }

    public T find(Object id, String[] controlAccess) throws MyException {
        checkAccessControl(controlAccess);
        return getEntityManager().find(entityClass, id);
    }

    public List<T> findAll(String[] controlAccess) throws MyException {
        checkAccessControl(controlAccess);
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        return getEntityManager().createQuery(cq).getResultList();
    }

    public List<T> findRange(int[] range, String[] controlAccess) throws MyException {
        checkAccessControl(controlAccess);
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        cq.select(cq.from(entityClass));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        q.setMaxResults(range[1] - range[0]);
        q.setFirstResult(range[0]);
        return q.getResultList();
    }

    public int count(String[] controlAccess) throws MyException {
        checkAccessControl(controlAccess);
        javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
        javax.persistence.criteria.Root<T> rt = cq.from(entityClass);
        cq.select(getEntityManager().getCriteriaBuilder().count(rt));
        javax.persistence.Query q = getEntityManager().createQuery(cq);
        return ((Long) q.getSingleResult()).intValue();
    }


    public List<T> querySelectStatement(String[] controlAccess, String statement) throws MyException {
        checkAccessControl(controlAccess);
        javax.persistence.Query q = null;
        if (statement.contains(":email")) {
            q = getEntityManager().createQuery(statement, entityClass).setParameter("email", controlAccess[2]);
        } else {
            q = getEntityManager().createQuery(statement, entityClass);
        }
        List l = q.getResultList();
        return l;
    }

    public int queryExecuteStatement(String[] controlAccess, String statement) throws MyException {
        checkAccessControl(controlAccess);
        javax.persistence.Query q = getEntityManager().createNativeQuery(statement);
        return q.executeUpdate();
    }

        public int queryExecuteStatement(String[] controlAccess, String statement, boolean onlyDBinfos) throws MyException {
        if (onlyDBinfos)
            checkOnlyDBinfos(controlAccess);
        else
            checkAccessControl(controlAccess);
            
        javax.persistence.Query q = getEntityManager().createNativeQuery(statement);
        return q.executeUpdate();
    }

    private boolean checkAccessControl(String[] controlAccess) throws MyException {
        if (controlAccess==null || controlAccess.length<4) {
            System.out.println("ERR_WRONG_DB_USER_LOGIN");
            throw new MyException(new MyErrMsg(MyException.INT_ERR_WRONG_DB_USER_LOGIN));
        }
        String userDB = controlAccess[0];
        String pwdDB = controlAccess[1];
        if (!this.userDB.equals(userDB) || !this.pwdDB.equals(pwdDB)) {
            System.out.println("ERR_WRONG_DB_USER_PWD");
            throw new MyException(new MyErrMsg(MyException.INT_ERR_WRONG_DB_USER_PWD));
        }
        String userAppli = controlAccess[2];
        String pwdAppli = controlAccess[3];
        try {
            String email = userAppli.toLowerCase().trim();
            EntityManager em = entityManagerFactory.createEntityManager();
            String userPwd = null;
            try {
                userPwd = (String) em.createNativeQuery("Select m.password from Member m where m.email='"+email+"'").getSingleResult();
            } finally {
                em.close();
            }
            if (userPwd==null) {
                System.out.println("ERR_WRONG_APPLI_USER_EMAIL");
                throw new MyException(new MyErrMsg(MyException.INT_ERR_WRONG_APPLI_USER_EMAIL));
            }
            if (!userPwd.equals(pwdAppli)) {
                System.out.println("ERR_WRONG_APPLI_USER_PWD");
                throw new MyException(new MyErrMsg(MyException.INT_ERR_WRONG_APPLI_USER_PWD));
            }
        } catch (Exception e) {
            System.out.println(e.getMessage());
            throw new MyException(e.getMessage());
        }
        return true;
    }
    private boolean checkOnlyDBinfos(String[] controlAccess) throws MyException {
        if (controlAccess==null || controlAccess.length<2) {
            System.out.println("ERR_WRONG_DB_USER_LOGIN");
            throw new MyException(new MyErrMsg(MyException.INT_ERR_WRONG_DB_USER_LOGIN));
        }
        String userDB = controlAccess[0];
        String pwdDB = controlAccess[1];
        if (!this.userDB.equals(userDB) || !this.pwdDB.equals(pwdDB)) {
            System.out.println("ERR_WRONG_DB_USER_PWD");
            throw new MyException(new MyErrMsg(MyException.INT_ERR_WRONG_DB_USER_PWD));
        }
        return true;
    }
}
